﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.IO;
using System.Xml.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Threading;

namespace SManage.TraceEngine
{
    [Serializable]
    public class SyncTaskPool:ICollection<SyncItem>,IEnumerable<SyncItem>,IDisposable
    {
        private static SortedSet<SyncItem> _pool = new SortedSet<SyncItem>();
        private Boolean _disposed;
        private Boolean _poolChanged;
        private static readonly SyncTaskPool _singleton = new SyncTaskPool();
        public event EventHandler<SyncItemChangedEventArgs> SyncItemChanged;

        private SyncTaskPool() {
            // Deserialize from file later
        }

        public static SyncTaskPool Default {
            get { return _singleton; }
        }

        public static void Load() {
            var poolSerializer = new BinaryFormatter();
            if (!Directory.Exists("Data")) {
                Directory.CreateDirectory("Data");
            }
            using (var stream = new FileStream(@"Data\SyncTask.bin", FileMode.Open)) {
                var loadPool = (SortedSet<SyncItem>)poolSerializer.Deserialize(stream);
                _pool = loadPool;
            }
        }

        public static void Save() {
            var poolSerializer = new BinaryFormatter();
            if (!Directory.Exists("Data")) {
                Directory.CreateDirectory("Data");
            }
            using (var stream = new FileStream(@"Data\SyncTask.bin", FileMode.Create)) {
                poolSerializer.Serialize(stream, _pool);
            }
        }

        public void OnSyncItemChanged(SyncItemChangedEventArgs e) {
            var handle = Interlocked.CompareExchange(ref SyncItemChanged, null, null);
            if (handle != null) {
                handle(this, e);
            }
        }

        #region Interface implement
        public void Add(SyncItem item) {
            if (item == null) {
                throw new ArgumentNullException("item", "item is null.");
            }
            _pool.Add(item);
            _poolChanged = true;
            OnSyncItemChanged(new SyncItemChangedEventArgs { Item = item });
        }

        public void Clear() {
            _pool.Clear();
            _poolChanged = true;
        }

        public bool Contains(SyncItem item) {
            if (item == null) {
                throw new ArgumentNullException("item", "item is null.");
            }
            return _pool.Contains(item);
        }

        public void CopyTo(SyncItem[] array, int arrayIndex) {
            if (array == null || array.Length == 0) {
                throw new ArgumentException("array is null or empty.", "array");
            }
            _pool.CopyTo(array, arrayIndex);
        }

        public int Count {
            get { return _pool.Count(); }
        }

        public bool IsReadOnly {
            get { return false; }
        }

        public bool Remove(SyncItem item) {
            if (item == null) {
                throw new ArgumentNullException("item", "item is null.");
            }
            var result = _pool.Remove(item);
            if (result) {
                _poolChanged = true;
            }
            return result;
        }

        public IEnumerator<SyncItem> GetEnumerator() {
            return _pool.GetEnumerator();
        }
        
        IEnumerator IEnumerable.GetEnumerator() {
            return ((IEnumerable)_pool).GetEnumerator();
        }
        #endregion

        public void Dispose() {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        ~SyncTaskPool() {
            Dispose(false);
        }

        protected virtual void Dispose(bool disposing) {
            if (_disposed) {
                return;
            }
            if (disposing) {
                if (_poolChanged) {
                    Save();
                    _poolChanged = false; 
                }                
            }
            _disposed = true;
        }
    }
}
